 package uk.co.mmscomputing.concurrent;
 
 public class ArrayBlockingQueue
 {
   protected Object[] buffer;
   protected int size;
   protected int front;
   protected int rear;
   protected boolean fcarry;
   protected boolean rcarry;
   protected Semaphore empty;
   protected Semaphore full;
   protected Object pt;
   protected Object gt;
 
   public ArrayBlockingQueue(int paramInt)
   {
     if (paramInt < 1) {
       throw new IllegalArgumentException(getClass().getName() + ".<init>(int init)\n\tParameter init must be greater than zero.");
     }
 
     this.buffer = new Object[paramInt];
     this.size = paramInt;
     this.front = 0; this.rear = 0;
     this.fcarry = false; this.rcarry = false;
     this.empty = new Semaphore(paramInt, true);
     this.full = new Semaphore(0, true);
     this.pt = new Object();
     this.gt = new Object();
   }
 
   public boolean isEmpty() {
     return (this.front == this.rear) && (this.fcarry == this.rcarry);
   }
 
   public boolean isFull() {
     return (this.front == this.rear) && (this.fcarry != this.rcarry);
   }
 
   public synchronized int size() {
     int i = this.front; int j = this.rear;
     if ((this.fcarry != this.rcarry) || (j < i)) j += this.size;
     return j - i;
   }
 
   public int remainingCapacity() {
     return this.size - size();
   }
 
   protected void add(Object paramObject) {
     this.buffer[this.rear] = paramObject;
     this.rear += 1; if (this.rear >= this.size) { this.rear -= this.size; this.rcarry = (!this.rcarry); }
   }
 
   public void put(Object paramObject) throws InterruptedException {
     this.empty.acquire();
     synchronized (this.pt) { add(paramObject); }
     this.full.release();
   }
 
   public boolean offer(Object paramObject) {
     try {
       return offer(paramObject, 0L, TimeUnit.MILLISECONDS);
     } catch (InterruptedException localInterruptedException) {
       localInterruptedException.printStackTrace();
     }return false;
   }
 
   public boolean offer(Object paramObject, long paramLong, TimeUnit paramTimeUnit)
     throws InterruptedException
   {
     if (paramObject == null) {
       throw new NullPointerException(getClass().getName() + ".offer(Object v,long timeout,TimeUnit unit)\n\tObject v is null.");
     }
     if (this.empty.tryAcquire(paramLong, paramTimeUnit)) {
       synchronized (this.pt) { add(paramObject); }
       this.full.release();
       return true;
     }
     return false;
   }
 
   protected Object remove() {
     Object localObject = this.buffer[this.front];
     this.front += 1; if (this.front >= this.size) { this.front -= this.size; this.fcarry = (!this.fcarry); }
     return localObject;
   }
 
   public Object take() throws InterruptedException
   {
     this.full.acquire();
     Object localObject1;
     synchronized (this.gt) { localObject1 = remove(); }
     this.empty.release();
     return localObject1;
   }
 
   public Object poll() {
     try {
       return poll(0L, TimeUnit.MILLISECONDS);
     } catch (InterruptedException localInterruptedException) {
       localInterruptedException.printStackTrace();
     }return null;
   }
 
   public Object poll(long paramLong, TimeUnit paramTimeUnit) throws InterruptedException
   {
     Object localObject1 = null;
     if (this.full.tryAcquire(paramLong, paramTimeUnit)) {
       synchronized (this.gt) { localObject1 = remove(); }
       this.empty.release();
     }
     return localObject1;
   }
   public void clear() {
     while (poll() != null);
   }
 }

